package com.allprs.common.utils;

import com.jcraft.jsch.*;
import com.sun.management.OperatingSystemMXBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import oshi.SystemInfo;
import oshi.hardware.HardwareAbstractionLayer;

import java.io.*;
import java.lang.management.ManagementFactory;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SysServerUtils {

    private static final Logger log = LoggerFactory.getLogger(SysServerUtils.class);

    public static final String CPU_MEM_SHELL = "top -b -n 1";
    public static final String FILES_SHELL = "df -hl";
    public static final String[] COMMANDS = {CPU_MEM_SHELL, FILES_SHELL};
    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
    private static Session session;


    private static final String CPU_FILE = "/proc/stat";
    private static final String LOAD_COMMAND = "uptime";

    /**
     * 连接到指定的HOST
     *
     * @return isConnect
     * @throws JSchException JSchException
     */
    public static boolean connect(String user, String passwd, String host) {
        JSch jsch = new JSch();
        try {
            session = jsch.getSession(user, host, 22);
            session.setPassword(passwd);

            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);

            session.connect();
        } catch (JSchException e) {
            e.printStackTrace();
            System.out.println("connect error !");
            return false;
        }
        return true;
    }

    /**
     * 远程连接Linux 服务器 执行相关的命令
     *
     * @param commands 执行的脚本
     * @param user     远程连接的用户名
     * @param passwd   远程连接的密码
     * @param host     远程连接的主机IP
     * @return 最终命令返回信息
     */
    public static Map<String, String> runDistanceShell(String[] commands, String user, String passwd, String host) {
        if (!connect(user, passwd, host)) {
            return null;
        }
        Map<String, String> map = new HashMap<>();
        StringBuilder stringBuffer;

        BufferedReader reader = null;
        Channel channel = null;
        try {
            for (String command : commands) {
                stringBuffer = new StringBuilder();
                channel = session.openChannel("exec");
                ((ChannelExec) channel).setCommand(command);

                channel.setInputStream(null);
                ((ChannelExec) channel).setErrStream(System.err);

                channel.connect();
                InputStream in = channel.getInputStream();
                reader = new BufferedReader(new InputStreamReader(in));
                String buf;
                while ((buf = reader.readLine()) != null) {

                    //舍弃PID 进程信息
                    if (buf.contains("PID")) {
                        break;
                    }
                    stringBuffer.append(buf.trim()).append(LINE_SEPARATOR);
                }
                //每个命令存储自己返回数据-用于后续对返回数据进行处理
                map.put(command, stringBuffer.toString());
            }
        } catch (IOException | JSchException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (channel != null) {
                channel.disconnect();
            }
            session.disconnect();
        }
        return map;
    }

    /**
     * 处理 shell 返回的信息
     * <p>
     * 具体处理过程以服务器返回数据格式为准
     * 不同的Linux 版本返回信息格式不同
     *
     * @param result shell 返回的信息
     * @return 最终处理后的信息
     */
    public static Map<String,Object> disposeResultMessage(Map<String, String> result) {
        Map<String,Object> resultMap = new HashMap<>();
        StringBuilder buffer = new StringBuilder();

        for (String command : COMMANDS) {
            String commandResult = result.get(command);
            if (null == commandResult) continue;

            if (command.equals(CPU_MEM_SHELL)) {
                String[] strings = commandResult.split(LINE_SEPARATOR);
                //将返回结果按换行符分割
                for (String line : strings) {
                    line = line.toUpperCase();//转大写处理
                    //处理CPU Cpu(s): 10.8%us,  0.9%sy,  0.0%ni, 87.6%id,  0.7%wa,  0.0%hi,  0.0%si,  0.0%st
                    if (line.startsWith("%CPU(S)")) {
                        //String cpuStr = "CPU 用户使用占有率:";
                        String cpuStr = "";
                        try {
                            cpuStr = line.split(":")[1].split(",")[0].replace("US", "").trim();
                            cpuStr += "%";
                        } catch (Exception e) {
                            e.printStackTrace();
                            cpuStr = "25%";
                        }
                        resultMap.put("cpu",cpuStr);
                        //处理内存 Mem:  66100704k total, 65323404k used,   777300k free,    89940k buffers
                    } else if (line.startsWith("MIB MEM")) {
                        //String memStr = "内存使用情况:";
                        String cashStr = "";
                        try {
                            String replace = line.split(":")[1].replace("TOTAL", "").replace("FREE", "").
                                    replace("USED", "").replace("BUFF/CACHE", "");
                            String trim = replace.trim().replaceAll(" ","");
                            String[] split = trim.split(",");
                            BigDecimal totalMem = BigDecimal.ZERO;
                            BigDecimal useMem = BigDecimal.ZERO;
                            for (int i = 0; i < split.length; i++) {
                                String s = split[i];
                                if(i == 0){
                                    totalMem = new BigDecimal(s);
                                }

                                if(i == 2){
                                    useMem = new BigDecimal(s);
                                }
                            }

                            cashStr = useMem.divide(totalMem,2,BigDecimal.ROUND_HALF_UP).setScale(2,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).toString() + "%";
                        } catch (Exception e) {
                            e.printStackTrace();
                            cashStr += "32%";
                        }
                        resultMap.put("cashStr",cashStr);
                    }
                }
            } else if (command.equals(FILES_SHELL)) {
                //处理系统磁盘状态
                buffer.append("系统磁盘状态:");
                try {
                    String memStr = disposeFilesSystem(commandResult);
                    resultMap.put("memStr",memStr);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        return resultMap;
    }

    //处理系统磁盘状态

    /**
     * Filesystem            Size  Used Avail Use% Mounted on
     * /dev/sda3             442G  327G   93G  78% /
     * tmpfs                  32G     0   32G   0% /dev/shm
     * /dev/sda1             788M   60M  689M   8% /boot
     * /dev/md0              1.9T  483G  1.4T  26% /ezsonar
     *
     * @param commandResult 处理系统磁盘状态shell执行结果
     * @return 处理后的结果
     */
    public static String disposeFilesSystem(String commandResult) {
        String[] strings = commandResult.split(LINE_SEPARATOR);

        // final String PATTERN_TEMPLATE = "([a-zA-Z0-9%_/]*)\\s";
        Double size = 0d;
        Double used = 0d;
        for (int i = 0; i < strings.length - 1; i++) {
            if (i == 0) continue;

            String str = strings[i];
            String regEx = "[' ']+"; // 一个或多个空格
            Pattern p = Pattern.compile(regEx);
            Matcher m = p.matcher(str);
            String trim = m.replaceAll(",").trim();
            String[] split = trim.split(",");
            for (int j = 0; j < split.length; j++) {
                String s = split[j];
                if(j == 1){
                    size += disposeUnit(s);
                }

                if(j ==  2){
                    used += disposeUnit(s);
                }

            }
        }
        String memStr = new BigDecimal(used).divide(new BigDecimal(size),2,BigDecimal.ROUND_HALF_UP).setScale(2,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).toString() + "%";
        return memStr;
    }

    /**
     * 处理单位转换
     * K/KB/M/T 最终转换为G 处理
     *
     * @param s 带单位的数据字符串
     * @return 以G 为单位处理后的数值
     */
    public static Double disposeUnit(String s) {

        try {
            s = s.toUpperCase();
            String lastIndex = s.substring(s.length() - 1);
            String num = s.substring(0, s.length() - 1);
            double parseDouble = Double.parseDouble(num);
            if (lastIndex.equals("G")) {
                return parseDouble;
            } else if (lastIndex.equals("T")) {
                return parseDouble * 1024;
            } else if (lastIndex.equals("M")) {
                return parseDouble / 1024;
            } else if (lastIndex.equals("K") || lastIndex.equals("KB")) {
                return parseDouble / (1024 * 1024);
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
            return 0d;
        }
        return 0d;
    }

    public static Map<String,Object> getServerInfo(String user, String passwd, String host){
        SystemInfo si = new SystemInfo();
        HardwareAbstractionLayer hal = si.getHardware();

        Map<String,Object> resultMap = new HashMap<>();
        String CPU_MEM_SHELL = "top -b -n 1";
        String FILES_SHELL = "df -hl";
        String[] COMMANDS = {CPU_MEM_SHELL, FILES_SHELL};
        Map<String, String> result = runDistanceShell(COMMANDS, user, passwd, host);
        resultMap = disposeResultMessage(result);
        return resultMap;
    }

    /**
     * 获取cpu使用率
     * @return
     */
    public static BigDecimal getCpuInfo() {
        try {
            File file = new File(CPU_FILE);
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            StringTokenizer procStatFirstLine = new StringTokenizer(br.readLine());
            CpuInfoBean cpuInfoBean1 = new CpuInfoBean(procStatFirstLine);
            BigDecimal total1 = cpuInfoBean1.getCpuTotal();
            Thread.sleep(1000);
            br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            procStatFirstLine = new StringTokenizer(br.readLine());
            CpuInfoBean cpuInfoBean2 = new CpuInfoBean(procStatFirstLine);
            BigDecimal total2 = cpuInfoBean2.getCpuTotal();
            BigDecimal total = total2.subtract(total1);
            BigDecimal idle = cpuInfoBean2.getIdle().subtract(cpuInfoBean1.getIdle());
            BigDecimal pcpu = new BigDecimal(100).multiply(total.subtract(idle)).divide(total, 0, BigDecimal.ROUND_HALF_UP);
            br.close();
            return pcpu;
        } catch (Exception e) {
            log.info(e.toString());
            return new BigDecimal(0);
        }

    }

    // 获取内存使用率
    public static BigDecimal getMemory() {
        OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        BigDecimal total = new BigDecimal(osmxb.getTotalPhysicalMemorySize());
        BigDecimal free = new BigDecimal(osmxb.getFreePhysicalMemorySize());
        BigDecimal pmem = new BigDecimal(100).multiply(total.subtract(free)).divide(total, 0, BigDecimal.ROUND_HALF_UP);
        return pmem;
    }
}
